/**
 * @file FreeRTOS_app.c
 * @author liufeng (liufeng@injoinic.com)
 * @brief FreeRTOS task.
 * @version 0.1
 * @date 2024-11-07
 *
 * @copyright Copyright (c) 2024  injoinic
 *
 */

#include "FreeRTOS_app.h"
#include "FreeRTOS.h"
#include "bsp_speaker_handler.h"
#include "queue.h"
#include "task.h"

TaskHandle_t StartTask_Handle = NULL; // 用于任务创建
TaskHandle_t PrintTask_Handle = NULL;
TaskHandle_t testTask_Handle = NULL;
TaskHandle_t KeyScanTask_Handle = NULL;
TaskHandle_t SpkTask_Handle = NULL;

void StartTask(void* argument);
extern void test_task();
void key_scan_task();

typedef struct
{
    void (*pxTaskCode)(void*);
    const char* const pcName;
    const uint16_t usStackDepth;
    void* const pvParameters;
    uint32_t uxPriority;
    void** const pxCreatedTask;
} task_attribute;

static const task_attribute task_table[] = {
    // {test_task, "test_task", 256, NULL, 1, &testTask_Handle},
    {key_scan_task, "key_scan_task", 128, NULL, 3, &KeyScanTask_Handle},
    {spk_handler_task, "spk_handler_task", 1024, NULL, 4, &SpkTask_Handle}
};

void FreeRTOS_app()
{
    BaseType_t xReturn = pdPASS;
    xReturn = xTaskCreate(StartTask, "StartTask", 128, NULL, 1, &StartTask_Handle);
    configASSERT(xReturn);

    vTaskStartScheduler();
}

/* -------------------------------------------------------------------------- */
/*                                   start任务                                 */
/* -------------------------------------------------------------------------- */

void StartTask(void* argument)
{
    taskENTER_CRITICAL(); // 进入临界区

    // 根据task_table结构体数组，创建所有任务
    uint16_t task_num = sizeof(task_table) / sizeof(task_attribute);
    for (uint16_t i = 0; i < task_num; i++) {
        BaseType_t xReturn = xTaskCreate(
            task_table[i].pxTaskCode,
            task_table[i].pcName,
            task_table[i].usStackDepth,
            task_table[i].pvParameters,
            task_table[i].uxPriority,
            task_table[i].pxCreatedTask
        );
        configASSERT(xReturn);
    }

    vTaskDelete(StartTask_Handle); // 使命完成，删除

    taskEXIT_CRITICAL();           // 退出临界区
}

/* -------------------------------------------------------------------------- */
/*                                   测试任务                                  */
/* -------------------------------------------------------------------------- */

#include "bsp_speaker_handler.h"

// 按键扫描，仅供speaker handler测试使用
void key_scan_task()
{
    list_voice_node test1 = {.priority = 3, .voice_address = 0x00, .volume = 0xE2};
    list_voice_node* p1 = &test1;
    xQueueSend(spk_handler.voice_add_queue, &p1, portMAX_DELAY);

    list_voice_node test2 = {.priority = 0, .voice_address = 0x01, .volume = 0xE4};
    list_voice_node* p2 = &test2;
    // xQueueSend(spk_handler.voice_add_queue, &p2, portMAX_DELAY);

    while (1) {
        if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET) {
            vTaskDelay(10);
            if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET) {
                // 按键按下，发送一个高优先级结点
                xQueueSend(spk_handler.voice_add_queue, &p2, portMAX_DELAY);
                while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET)
                    ; // 等待释放，防止多次发送
            }
        }
        vTaskDelay(100);
    }
}
